package com.googlecode.continuity.core.server;

import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.DefaultPropertiesPersister;

/**
 * SimplePropertiesPersister offers a basic implementation to save a set of properties to a file.
 *
 * @author Peter Schmitt <aragos@aragos.de>
 */
public class SimplePropertiesPersister extends DefaultPropertiesPersister implements ResourceLoaderAware {
// ------------------------------ FIELDS ------------------------------

  /**
   * Logger for this class and subclasses
   */
  protected final Log logger = LogFactory.getLog(getClass());
  private ResourceLoader resourceLoader;

// --------------------- GETTER / SETTER METHODS ---------------------

  /**
   * Sets a new resource loader that will be used to access files.
   *
   * @param resourceLoader new resource loader
   */
  public void setResourceLoader(ResourceLoader resourceLoader) {
    this.resourceLoader = resourceLoader;
  }

// -------------------------- OTHER METHODS --------------------------

  /**
   * Saves a set of key-value pairs into an existing file using the properties format.  If the key already exists it
   * overwrites the old value, otherwise the new key is added to the file.
   *
   * @param properties list of key-value pairs
   * @param fileName existing file to which the properties are to be saved
   */
  public void saveOrUpdate(Map<String, String> properties, String fileName) {
    // TODO: make header something meaningful
    String header = "";
    Resource resource = resourceLoader.getResource(fileName);
    Properties props = new Properties();
    if (!resource.exists()) {
      if (logger.isDebugEnabled()) {
        logger.debug("No properties file found for [" + fileName + "]");
      }
      return;
    }

    // load properties
    try {
      InputStream is = resource.getInputStream();
      try {
        // TODO: add encoding
        if (logger.isDebugEnabled()) {
          logger.debug("Loading properties [" + resource.getFilename() + "]");
        }
        load(props, is);
      } finally {
        is.close();
      }
    } catch (IOException e) {
      if (logger.isWarnEnabled()) {
        logger.warn("Could not parse properties file [" + resource.getFilename() + "]: " + e.getMessage(), e);
      }
      return;
    }

    // add/update properties
    for (Map.Entry<String, String> entry : properties.entrySet()) {
      props.setProperty(entry.getKey(), entry.getValue());
    }

    // save properties
    try {
      FileWriter writer = new FileWriter(resource.getFile());
      try {
        // TODO: add encoding?
        if (logger.isDebugEnabled()) {
          logger.debug("Saving properties [" + resource.getFilename() + "]");
        }
        store(props, writer, header);
      } finally {
        writer.close();
      }
    } catch (IOException e) {
      if (logger.isWarnEnabled()) {
        logger.warn("Could not write to properties file [" + resource.getFilename() + "]: " + e.getMessage(), e);
      }
    }
  }
}
